package com.hengshan.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hengshan.common.enums.ReturnCode;
import com.hengshan.common.utils.BeanCopyUtil;
import com.hengshan.common.utils.SecurityUtils;
import com.hengshan.domain.entity.User;
import com.hengshan.domain.entity.UserRole;
import com.hengshan.domain.vo.PageVo;
import com.hengshan.domain.vo.UserInfoVo;
import com.hengshan.exception.SystemException;
import com.hengshan.mapper.UserMapper;
import com.hengshan.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 用户表(User)表服务实现类
 *
 * @author muxijun
 * @since 2023-12-07 18:34:20
 */
@Service("userService")
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    public static final int USER_STATUS_ON = 1; // 用户状态正常

    private final UserMapper userMapper;
    private final PasswordEncoder passwordEncoder;
    private final UserRoleServiceImpl userRoleService;

    @Override
    @Transactional
    public boolean deleteByIds(List<Long> ids) {
        LambdaQueryWrapper<UserRole> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(UserRole::getUserId, ids);
        return userRoleService.remove(queryWrapper) && removeBatchByIds(ids);
    }

    @Override
    @Transactional
    public boolean deleteById(Long id) {
        LambdaQueryWrapper<UserRole> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserRole::getUserId, id);
        return userRoleService.remove(queryWrapper) && removeById(id);
    }

    @Override
    public PageVo<UserInfoVo> getList(int pageNum, int pageSize, String username) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        // queryWrapper.eq(User::getStatus, USER_STATUS_ON);
        queryWrapper.like(StringUtils.hasText(username), User::getUsername, username);
        Page<User> page = new Page<>(pageNum, pageSize);
        page(page, queryWrapper);
        List<UserInfoVo> list = BeanCopyUtil.copyBeanList(page.getRecords(), UserInfoVo.class);
        return new PageVo<>(list, page.getTotal());
    }

    @Override
    public UserInfoVo getOneById(Long id) {
        User user = userMapper.selectById(id);
        return BeanCopyUtil.copyBean(user, UserInfoVo.class);
    }

    @Override
    @Transactional
    public UserInfoVo add(User user) {
        checkUnique(user);
        //密码加密
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        save(user);
        //添加用户角色关联信息
        //List<UserRole> userRoles = user.getRoles().stream().map(role -> new UserRole(user.getId(), role.getId())).collect(Collectors.toList());
        List<UserRole> userRoles = Arrays.stream(user.getRoleIds()).map(roleId -> new UserRole(user.getId(), roleId)).collect(Collectors.toList());
        userRoleService.saveBatch(userRoles);
        User tempUser = userMapper.selectById(user.getId());
        return BeanCopyUtil.copyBean(tempUser, UserInfoVo.class);
    }

    @Override
    @Transactional
    public UserInfoVo update(User user) {
        checkUnique(user);
        //使用updateById更新时，前端不要传时间参数，数据库时间会被unix初始时间覆盖掉
        updateById(user);
        if (user.getRoleIds().length>0) {
            //List<UserRole> userRoles = user.getRoles().stream().map(role -> new UserRole(user.getId(), role.getId())).collect(Collectors.toList());
            List<UserRole> userRoles = Arrays.stream(user.getRoleIds()).map(roleId -> new UserRole(user.getId(), roleId)).collect(Collectors.toList());
            LambdaQueryWrapper<UserRole> queryWrapper = new LambdaQueryWrapper<>();
            userRoleService.remove(queryWrapper.eq(UserRole::getUserId, user.getId()));
            userRoleService.saveBatch(userRoles);
        }
        User tempUser = userMapper.selectById(user.getId());
        return BeanCopyUtil.copyBean(tempUser, UserInfoVo.class);
    }

    @Override
    public void checkUnique(User user) {
        //校验用户名，邮箱，手机号是否已存在
        if (StringUtils.hasText(user.getUsername())) {
            boolean checkUsername = userMapper.exists(new LambdaQueryWrapper<User>()
                    .eq(User::getUsername, user.getUsername())
                    .ne(user.getId() != null, User::getId, user.getId()));
            if (checkUsername) {
                throw new SystemException(ReturnCode.USERNAME_EXIST);
            }
        }
        if (StringUtils.hasText(user.getEmail())) {
            boolean checkEmail = userMapper.exists(new LambdaQueryWrapper<User>()
                    .eq(User::getEmail, user.getEmail())
                    .ne(user.getId() != null, User::getId, user.getId()));
            if (checkEmail) {
                throw new SystemException(ReturnCode.EMAIL_EXIST);
            }
        }
        if (StringUtils.hasText(user.getPhone())) {
            boolean checkPhone = userMapper.exists(new LambdaQueryWrapper<User>()
                    .eq(User::getPhone, user.getPhone())
                    .ne(user.getId() != null, User::getId, user.getId()));
            if (checkPhone) {
                throw new SystemException(ReturnCode.PHONE_NUMBER_EXIST);
            }
        }
    }

    @Override
    public int resetPwd(User user) {
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        return userMapper.updateById(user);
    }

    @Override
    public int updateUserStatus(User user) {
        return userMapper.updateById(user);
    }

    /**
     * 校验用户是否允许操作
     *
     * @param user 用户信息
     */
    public void checkUserAllowed(User user) {
        if (user.isAdmin()) {
            throw new SystemException(ReturnCode.ACCESS_DENIED.getCode(), "不允许操作超级管理员用户");
        }
    }

    /**
     * 修改用户基本信息
     *
     * @param user 用户信息
     */
    public int updateUserProfile(User user) {
        checkUnique(user);
        return userMapper.updateById(user);
    }

    /**
     * 修改用户密码
     *
     * @param userId   用户id
     * @param password 密码
     */
    public int resetUserPwd(Long userId, String password) {
        String encodePassword = passwordEncoder.encode(password);
        return userMapper.update(null,
                new LambdaUpdateWrapper<User>()
                        .set(User::getPassword, encodePassword)
                        .eq(User::getId, userId));
    }

    /**
     * 修改用户头像
     *
     * @param userId 用户id
     * @param avatar 头像地址
     */
    public boolean updateUserAvatar(Long userId, String avatar) {
        return baseMapper.update(null,
                new LambdaUpdateWrapper<User>()
                        .set(User::getAvatar, avatar)
                        .eq(User::getId, userId)) > 0;
    }

    /**
     * 通过用户名查询用户
     *
     * @param userName 用户名
     * @return 用户对象信息
     */
    public User selectUserByUserName(String userName) {
        return userMapper.selectOne(new LambdaQueryWrapper<User>()
                .eq(User::getUsername, userName));
    }

    @Override
    public List<User> exportExcel() {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(User::getUsername, User::getPhone, User::getEmail, User::getSex)
                .eq(User::getStatus, USER_STATUS_ON);
        return list(wrapper);
    }

    public PageVo<User> selectAllocatedList(int pageNum, int pageSize, int roleId, String username, String phone) {
        Page<User> page = new Page<>(pageNum, pageSize);
        //一定要手动关闭SQL优化，不然查询总数的时候只会查询主表
        page.setOptimizeCountSql(false);
        IPage<User> ipage = userMapper.selectAllocatedList(page,roleId,username,phone);
        return new PageVo<>(ipage.getRecords(), ipage.getTotal());
    }

    public PageVo<User> selectUnallocatedList(int pageNum, int pageSize, int roleId, String username, String phone) {
        Page<User> page = new Page<>(pageNum, pageSize);
        page.setOptimizeCountSql(false);
        IPage<User> ipage = userMapper.selectUnallocatedList(page,roleId,username,phone);
        return new PageVo<>(ipage.getRecords(), ipage.getTotal());
    }
}

